{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "e42d10bb-8217-4d6b-a8ad-f072340d9c23",
   "metadata": {},
   "outputs": [],
   "source": [
    "import random as rd\n",
    "from math import exp, cos, pi\n",
    "from copy import deepcopy\n",
    "import numpy as np\n",
    "import pandas as pd"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5779d32c-4cb0-4ebf-81fc-debcd4d24ab1",
   "metadata": {},
   "source": [
    "## 基于飞蛾扑火优化算法的股票组合权重优化"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7bd50d80-343d-40d0-a2b7-d0fc90fe472f",
   "metadata": {},
   "source": [
    "导入数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "ed63eb37-26ac-4c73-bd9f-81bba557091c",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "D:\\Anaconda3\\lib\\site-packages\\openpyxl\\styles\\stylesheet.py:221: UserWarning: Workbook contains no default style, apply openpyxl's default\n",
      "  warn(\"Workbook contains no default style, apply openpyxl's default\")\n"
     ]
    }
   ],
   "source": [
    "# 指数权重前20的成分股近3年每天的数据\n",
    "df=pd.read_excel(\"df_all_top_20.xlsx\",index_col=0)\n",
    "# 指数权重前20的成分股近3年收盘时序数据\n",
    "df1=pd.pivot_table(df,index=[\"trade_date\",\"ts_code\"],values=[\"pct_chg\"])\n",
    "df2=pd.pivot_table(df,index=[\"trade_date\",\"ts_code\"],values=[\"close\",\"pre_close\"])\n",
    "# 沪深300指数基本数据\n",
    "df300=pd.read_excel(\"df_300_w.xlsx\",index_col=0)\n",
    "df20=df300.loc[:19,:] # 指数权重前20的成分股基本数据\n",
    "# 沪深300指数近3年每天的数据\n",
    "df300_daily=pd.read_excel('沪深300指数近3年.xlsx')\n",
    "\n",
    "ts_code_20=df20['ts_code'].tolist()\n",
    "close300=df300_daily[['日期Date','收盘Close']]\n",
    "index2codes=ts_code_20\n",
    "closei=df2"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e4ecae27-b3c4-4067-aea9-d9404eba1fb5",
   "metadata": {},
   "source": [
    "定义mfo"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "31710ef6-c748-4c04-817f-677ee78c3e64",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 基于飞蛾扑火优化算法的股票组合权重优化\n",
    "class MFO:\n",
    "    def __init__(self,n,iter,dim,ub,lb,chgi,chg300,index2codes,p,choose_obj):\n",
    "        self.choose_obj=choose_obj # 选择什么目标函数\n",
    "        self.pop=n # 种群个数\n",
    "        # self.func=func\n",
    "        self.iter=iter\n",
    "        self.dim=dim # 个体维度\n",
    "        self.ub=ub\n",
    "        self.lb=lb\n",
    "        self.chgi=chgi # 成分股当日涨跌幅, df透视表类型，index=[日期，股票代码]，values=[chg]\n",
    "        self.chg300=chg300 # 沪深300指数当日涨跌幅,df类型[日期，chg]\n",
    "        self.sigma=1 # 惩罚参数\n",
    "        self.p=p # 惩罚因子\n",
    "        self.index2codes=index2codes # 20支股票代码的列表\n",
    "\n",
    "        # 算法参数\n",
    "        self.b=1 # 对数螺旋形状常数\n",
    "        self.N = 10; # 火焰的最大数量\n",
    "\n",
    "    def ini_population(self):\n",
    "        # 初始化种群\n",
    "        # 都是np.array类型\n",
    "        population=np.empty((self.pop,self.dim))\n",
    "        for i in range(self.pop):\n",
    "            moth=np.empty((self.dim,),dtype=list)\n",
    "            # sum_i=0\n",
    "            for j in range(self.dim):\n",
    "                moth[j]=rd.uniform(0,0.1) # 随机\n",
    "                # sum_i+=moth[j]\n",
    "            population[i,:]=moth\n",
    "        return population\n",
    "\n",
    "    def getFitness(self,moths):\n",
    "        # fitness = np.empty((len(moths),),dtype=list)\n",
    "        # for i in range(len(moths)):\n",
    "        if self.choose_obj==1:\n",
    "            fitness=self.objFunction(moths)\n",
    "        else:\n",
    "            fitness=self.objFunction2(moths)\n",
    "        # print('第',i,'个已完成')\n",
    "        # fitness=np.array(fitness)\n",
    "        return fitness\n",
    "\n",
    "    def objFunction(self,moth):\n",
    "        # 最小化涨跌幅绝对误差之和\n",
    "        days=len(self.chg300)\n",
    "        abs_error=0\n",
    "        for i in range(days):\n",
    "            # 计算20支股票组合的当日涨跌幅\n",
    "            chg_i=0\n",
    "            date=self.chg300.loc[i,'日期Date']\n",
    "            str_query='trade_date == ['+ str(date)+']'\n",
    "            df_i=self.chgi.query(str_query)\n",
    "            df_i=df_i.reset_index()\n",
    "            for j in range(len(moth)):\n",
    "                # 根据索引找到股票代码，然后找到当日chg\n",
    "                item=df_i[df_i['ts_code']==self.index2codes[j]]\n",
    "                if not item.empty:\n",
    "                    chg_i_j=np.sum(item['pct_chg']/100)\n",
    "                else:\n",
    "                    # 这只股票当天没数据的话就等于0\n",
    "                    chg_i_j=0\n",
    "                chg_i+=chg_i_j*moth[j]\n",
    "            # 找到当日沪深300的涨跌幅\n",
    "            chg300_i=self.chg300.loc[i,'涨跌幅(%)Change(%)']/100\n",
    "            # 当日涨跌幅绝对误差(单位：1)\n",
    "            abs_error_i=np.abs(chg300_i-chg_i)\n",
    "\n",
    "            # 求和\n",
    "            abs_error+=abs_error_i\n",
    "\n",
    "            # print('days=',date)\n",
    "\n",
    "        # 加惩罚项：moth求和=1\n",
    "        P=0.5*self.sigma*np.square(np.sum(moth)-1)\n",
    "\n",
    "        objFunctionValue=abs_error+P\n",
    "\n",
    "        return objFunctionValue\n",
    "\n",
    "    def objFunction2(self,x):\n",
    "        # 最小化跟踪误差\n",
    "        days=len(close300)\n",
    "        track_error=0\n",
    "        earning_rate=[]\n",
    "        for i in range(days):\n",
    "            if i==0:\n",
    "                continue\n",
    "            # 计算20支股票组合的当日收益率：(当日收盘价 - 前一日收盘价) / 前一日收盘价\n",
    "            earning_rate_i=0\n",
    "            date=close300.loc[i,'日期Date']\n",
    "            str_query='trade_date == ['+ str(date)+']'\n",
    "            df_i=closei.query(str_query)\n",
    "            df_i=df_i.reset_index()\n",
    "            for j in range(len(x)):\n",
    "                # 根据索引找到股票代码，然后计算当日收益率\n",
    "                item=df_i[df_i['ts_code']==index2codes[j]]\n",
    "                if not item.empty:\n",
    "                    earning_rate_i_j=np.sum((item['close']-item['pre_close'])/item['pre_close'])\n",
    "                else:\n",
    "                    # 这只股票当天没数据的话就等于0\n",
    "                    earning_rate_i_j=0\n",
    "                earning_rate_i+=earning_rate_i_j*x[j]\n",
    "            # 找到当日沪深300的收益率\n",
    "            earning_rate300_i=(close300.loc[i,'收盘Close']-close300.loc[i-1,'收盘Close'])/close300.loc[i-1,'收盘Close']\n",
    "            # 当日跟踪误差误差(单位：1)\n",
    "            earning_rate.append(earning_rate_i-earning_rate300_i)\n",
    "        # 求标准差\n",
    "        track_error=np.std(earning_rate)        \n",
    "        # 加惩罚项：moth求和=1\n",
    "        P=0.5*self.sigma*np.square(np.sum(x)-1)\n",
    "        objFunctionValue=track_error+P\n",
    "        return objFunctionValue\n",
    "\n",
    "    def check(self,x):\n",
    "        if x < 0:\n",
    "            return 0\n",
    "        elif x > 1:\n",
    "            return 1\n",
    "        else:\n",
    "            return x\n",
    "\n",
    "    def run(self):\n",
    "        n=self.pop # 种群个数\n",
    "        dim=self.dim\n",
    "        b=self.b\n",
    "        N=self.N\n",
    "        iterx, max_iter = 0, self.iter\n",
    "\n",
    "        X0=self.ini_population() # 初始种群位置\n",
    "\n",
    "        fit = np.empty((n,),dtype=list)\n",
    "        for i in range(n):\n",
    "            fit[i]=self.getFitness(X0[i,:]) # 初始每个个体的适应值\n",
    "            # print('第',i,'个已完成')\n",
    "\n",
    "        Moth_pos = X0 # 记录更新后的飞蛾位置\n",
    "        curve = np.empty((max_iter,),dtype=list) # 记录每一代的最佳适应度\n",
    "        best_pos = np.zeros((max_iter,dim)) # 记录每一代飞蛾能达到的最佳位置\n",
    "\n",
    "        while iterx < max_iter:\n",
    "            flame_no=rd.randint(1,int(N-iterx*(N-1)/max_iter)) # 计算本次迭代的火焰数量\n",
    "\n",
    "            if iterx == 0:\n",
    "                index = np.argsort(fit)\n",
    "                fit= fit[index]; # 求最小值按照ascend的排序\n",
    "                flame_pos = np.zeros((flame_no,dim))\n",
    "                flame_fit = np.empty((flame_no,),dtype=list)\n",
    "                for i in range(flame_no):\n",
    "                    flame_pos[i,:]=X0[index[i],:] # 记录第一代火焰位置\n",
    "                    flame_fit[i] = self.getFitness(X0[index[i],:])\n",
    "            \n",
    "            # 更新飞蛾位置\n",
    "            for i in range(n):\n",
    "                for j in range(dim):\n",
    "                    a=-1+iterx*((-1)/max_iter)\n",
    "                    t = rd.uniform(a, 1)\n",
    "                    if i <flame_no:\n",
    "                        distance=abs(flame_pos[i][j] - Moth_pos[i][j])\n",
    "                        Moth_pos[i][j]=distance * exp(b * t) * cos(2 * pi * t) + flame_pos[i][j]\n",
    "                        Moth_pos[i][j]=self.check(Moth_pos[i][j])\n",
    "                    else:\n",
    "                        distance=abs(flame_pos[0][j] - Moth_pos[i][j])\n",
    "                        Moth_pos[i][j]=distance * exp(b * t) * cos(2 * pi * t) + flame_pos[0][j]\n",
    "                        Moth_pos[i][j]=self.check(Moth_pos[i][j])\n",
    "                # 更新飞蛾适应度\n",
    "                fit[i]=self.getFitness(Moth_pos[i,:])\n",
    "            \n",
    "            # 将更新后的飞蛾位置与火焰位置的适应度重新排序\n",
    "            double_pop=np.vstack((Moth_pos,flame_pos))\n",
    "            double_fitness=np.hstack((fit,flame_fit))\n",
    "            # 排序\n",
    "            double_index = np.argsort(double_fitness)\n",
    "            double_fitness_sorted=double_fitness[double_index]\n",
    "            double_sorted_pop= double_pop[double_index,:]\n",
    "            # 更新下一代火焰位置\n",
    "            flame_fit=double_fitness_sorted[:N]\n",
    "            flame_pos = double_sorted_pop[:N,:]\n",
    "\n",
    "            curve[iterx] = flame_fit[0] # 记录当代最佳适应度\n",
    "            best_pos[iterx,:] =flame_pos[0,:] # 记录当代最佳位置\n",
    "            best_score = curve[-1]# 记录最佳适应值\n",
    "\n",
    "            print(\"迭代第\",iterx,\"次，best_score=\",curve[iterx] )\n",
    "\n",
    "            iterx+=1\n",
    "            # 更新惩罚参数\n",
    "            self.sigma=self.p*self.sigma\n",
    "\n",
    "        return best_pos,best_score,curve"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5d737b88-b164-42a9-8680-c8407e943694",
   "metadata": {},
   "source": [
    "### 1. 最小化涨跌幅绝对误差之和"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "fdbb194a-4aab-433e-9621-16b7cbcb6369",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "迭代第 0 次，best_score= 2.272675092485652\n",
      "迭代第 1 次，best_score= 2.2089247500433142\n",
      "迭代第 2 次，best_score= 2.2007322185104248\n",
      "迭代第 3 次，best_score= 2.2007322185104248\n",
      "迭代第 4 次，best_score= 2.2007322185104248\n",
      "迭代第 5 次，best_score= 2.2007322185104248\n",
      "迭代第 6 次，best_score= 2.2007322185104248\n",
      "迭代第 7 次，best_score= 2.2007322185104248\n",
      "迭代第 8 次，best_score= 2.2007322185104248\n",
      "迭代第 9 次，best_score= 2.2007322185104248\n",
      "best_pos: [[0.05926205 0.13512036 0.06878236 0.1031403  0.06799468 0.14960229\n",
      "  0.03727958 0.06869446 0.10841577 0.0631211  0.06593863 0.01358416\n",
      "  0.02646112 0.         0.03227461 0.         0.         0.05354724\n",
      "  0.04738318 0.01454129]\n",
      " [0.06216798 0.12957148 0.07519792 0.02380877 0.04605627 0.13981376\n",
      "  0.02937324 0.11003972 0.03203279 0.06145386 0.07813051 0.01322412\n",
      "  0.02520018 0.         0.0419789  0.         0.         0.11664168\n",
      "  0.04805863 0.00924589]\n",
      " [0.06167974 0.13508307 0.07584419 0.00526664 0.05117638 0.14300095\n",
      "  0.03125425 0.10783151 0.00564901 0.04431741 0.08270373 0.01985895\n",
      "  0.04278585 0.         0.04044439 0.         0.         0.09223958\n",
      "  0.03526145 0.        ]\n",
      " [0.06167974 0.13508307 0.07584419 0.00526664 0.05117638 0.14300095\n",
      "  0.03125425 0.10783151 0.00564901 0.04431741 0.08270373 0.01985895\n",
      "  0.04278585 0.         0.04044439 0.         0.         0.09223958\n",
      "  0.03526145 0.        ]\n",
      " [0.06167974 0.13508307 0.07584419 0.00526664 0.05117638 0.14300095\n",
      "  0.03125425 0.10783151 0.00564901 0.04431741 0.08270373 0.01985895\n",
      "  0.04278585 0.         0.04044439 0.         0.         0.09223958\n",
      "  0.03526145 0.        ]\n",
      " [0.06167974 0.13508307 0.07584419 0.00526664 0.05117638 0.14300095\n",
      "  0.03125425 0.10783151 0.00564901 0.04431741 0.08270373 0.01985895\n",
      "  0.04278585 0.         0.04044439 0.         0.         0.09223958\n",
      "  0.03526145 0.        ]\n",
      " [0.06167974 0.13508307 0.07584419 0.00526664 0.05117638 0.14300095\n",
      "  0.03125425 0.10783151 0.00564901 0.04431741 0.08270373 0.01985895\n",
      "  0.04278585 0.         0.04044439 0.         0.         0.09223958\n",
      "  0.03526145 0.        ]\n",
      " [0.06167974 0.13508307 0.07584419 0.00526664 0.05117638 0.14300095\n",
      "  0.03125425 0.10783151 0.00564901 0.04431741 0.08270373 0.01985895\n",
      "  0.04278585 0.         0.04044439 0.         0.         0.09223958\n",
      "  0.03526145 0.        ]\n",
      " [0.06167974 0.13508307 0.07584419 0.00526664 0.05117638 0.14300095\n",
      "  0.03125425 0.10783151 0.00564901 0.04431741 0.08270373 0.01985895\n",
      "  0.04278585 0.         0.04044439 0.         0.         0.09223958\n",
      "  0.03526145 0.        ]\n",
      " [0.06167974 0.13508307 0.07584419 0.00526664 0.05117638 0.14300095\n",
      "  0.03125425 0.10783151 0.00564901 0.04431741 0.08270373 0.01985895\n",
      "  0.04278585 0.         0.04044439 0.         0.         0.09223958\n",
      "  0.03526145 0.        ]]\n",
      "best_score: 2.2007322185104248\n",
      "curve: [2.272675092485652 2.2089247500433142 2.2007322185104248\n",
      " 2.2007322185104248 2.2007322185104248 2.2007322185104248\n",
      " 2.2007322185104248 2.2007322185104248 2.2007322185104248\n",
      " 2.2007322185104248]\n"
     ]
    }
   ],
   "source": [
    "# 方法：飞蛾扑火优化算法\n",
    "lb=np.array([0]*20) # 下界\n",
    "ub=np.array([1]*20) # 上界\n",
    "max_i=10\n",
    "dim=20\n",
    "pop=50\n",
    "chgi=df1\n",
    "chg300=df300_daily[['日期Date','涨跌幅(%)Change(%)']]\n",
    "p=10 # 惩罚因子\n",
    "index2codes=ts_code_20\n",
    "\n",
    "mymfo=MFO(pop,max_i,dim,ub,lb,chgi,chg300,index2codes,p,1)\n",
    "\n",
    "best_pos,best_score,curve=mymfo.run()\n",
    "\n",
    "print('best_pos:',best_pos)\n",
    "print('best_score:',best_score)\n",
    "print('curve:',curve)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dd7dbb50-bd2c-4ebd-b9a0-d1cf9a5d51cd",
   "metadata": {},
   "source": [
    "评价指标"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "87fe74ff-2271-4cd5-a5a5-7775f0525ea1",
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_total_return(x):\n",
    "    # 计算收益率\n",
    "    days=len(close300)\n",
    "    total_return=0\n",
    "    daily_returns=[]\n",
    "    track_error=0\n",
    "    earning_rate=[]\n",
    "    for i in range(days):\n",
    "        if i==0:\n",
    "            continue\n",
    "        # 计算20支股票组合的当日收益率：(当日收盘价 - 前一日收盘价) / 前一日收盘价\n",
    "        earning_rate_i=0\n",
    "        date=close300.loc[i,'日期Date']\n",
    "        str_query='trade_date == ['+ str(date)+']'\n",
    "        df_i=closei.query(str_query)\n",
    "        df_i=df_i.reset_index()\n",
    "        for j in range(len(x)):\n",
    "            # 根据索引找到股票代码，然后计算当日收益率\n",
    "            item=df_i[df_i['ts_code']==index2codes[j]]\n",
    "            if not item.empty:\n",
    "                earning_rate_i_j=np.sum((item['close']-item['pre_close'])/item['pre_close'])\n",
    "            else:\n",
    "                # 这只股票当天没数据的话就等于0\n",
    "                earning_rate_i_j=0\n",
    "            earning_rate_i+=earning_rate_i_j*x[j]\n",
    "\n",
    "        # 找到当日沪深300的收益率\n",
    "        earning_rate300_i=(close300.loc[i,'收盘Close']-close300.loc[i-1,'收盘Close'])/close300.loc[i-1,'收盘Close']\n",
    "        # 当日跟踪误差误差(单位：1)\n",
    "        earning_rate.append(earning_rate_i-earning_rate300_i)\n",
    "        total_return+=earning_rate_i\n",
    "        daily_returns.append(earning_rate_i)\n",
    "    daily_returns=np.array(daily_returns)\n",
    "    # 求标准差\n",
    "    track_error=np.std(earning_rate)\n",
    "    return total_return,daily_returns,track_error"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "90afb926-76e1-4b19-b352-121ffe3e1b8b",
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_index(x):\n",
    "    eva_index={}\n",
    "    # 该组合跟踪误差\n",
    "    total_return,daily_returns,track_error=get_total_return(x)\n",
    "    eva_index['跟踪误差']=track_error\n",
    "    \n",
    "    # 年化收益率\n",
    "    n=3 # 取的是近3年的数据\n",
    "    annualized_return = (1 + total_return) ** (1 / n) - 1\n",
    "    eva_index['年化收益率']=annualized_return\n",
    "    \n",
    "    # 年化波动率\n",
    "    # 计算日波动率（日收益率的标准差）\n",
    "    daily_volatility=np.std(daily_returns, ddof=1)\n",
    "    # 将日波动率年化\n",
    "    annualized_volatility=daily_volatility * np.sqrt(252)\n",
    "    eva_index['年化波动率']=annualized_volatility\n",
    "    \n",
    "    # 夏普比率=（策略年化收益率 - 无风险年化收益率 ） / 策略年化波动率\n",
    "    R_p = annualized_return  # 投资组合年化回报率\n",
    "    R_f = 0.0125  # 无风险利率：3年期国债收益率\n",
    "    sigma_p = annualized_volatility  # 投资组合的年化波动率\n",
    "    sharpe_ratio = (R_p - R_f) / sigma_p\n",
    "    eva_index['夏普比率']=sharpe_ratio\n",
    "    return eva_index"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "877ed023-51b7-4ea2-8175-2ae95b1a0f1a",
   "metadata": {},
   "outputs": [],
   "source": [
    "x=best_pos[-1]\n",
    "eva_index=get_index(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "98b9c641-f582-4100-8cb6-35b83043f719",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'跟踪误差': 0.003973507353727158,\n",
       " '年化收益率': 0.065654417917276,\n",
       " '年化波动率': 0.1715380885782075,\n",
       " '夏普比率': 0.30986947772268014}"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "eva_index"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "95ed83b3",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.9743971002578969"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sum(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "638e1da0-59e1-4e3f-8f7c-435ec46812bd",
   "metadata": {},
   "source": [
    "### 2. 最小化跟踪误差"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "e684ee6b-0f91-400e-ba01-b5a0c43c0fb0",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "迭代第 0 次，best_score= 0.004486362561372005\n",
      "迭代第 1 次，best_score= 0.004486362561372005\n",
      "迭代第 2 次，best_score= 0.004486362561372005\n",
      "迭代第 3 次，best_score= 0.004486362561372005\n",
      "迭代第 4 次，best_score= 0.004486362561372005\n",
      "迭代第 5 次，best_score= 0.004486362561372005\n",
      "迭代第 6 次，best_score= 0.004486362561372005\n",
      "迭代第 7 次，best_score= 0.004486362561372005\n",
      "迭代第 8 次，best_score= 0.004486362561372005\n",
      "迭代第 9 次，best_score= 0.004486362561372005\n",
      "best_pos: [[0.00246808 0.09610023 0.08574116 0.06107258 0.06212572 0.01112134\n",
      "  0.0817503  0.07705903 0.13927416 0.06998187 0.03694651 0.\n",
      "  0.07654787 0.02045957 0.         0.0703855  0.         0.09456023\n",
      "  0.         0.01671482]\n",
      " [0.00246808 0.09610023 0.08574116 0.06107258 0.06212572 0.01112134\n",
      "  0.0817503  0.07705903 0.13927416 0.06998187 0.03694651 0.\n",
      "  0.07654787 0.02045957 0.         0.0703855  0.         0.09456023\n",
      "  0.         0.01671482]\n",
      " [0.00246808 0.09610023 0.08574116 0.06107258 0.06212572 0.01112134\n",
      "  0.0817503  0.07705903 0.13927416 0.06998187 0.03694651 0.\n",
      "  0.07654787 0.02045957 0.         0.0703855  0.         0.09456023\n",
      "  0.         0.01671482]\n",
      " [0.00246808 0.09610023 0.08574116 0.06107258 0.06212572 0.01112134\n",
      "  0.0817503  0.07705903 0.13927416 0.06998187 0.03694651 0.\n",
      "  0.07654787 0.02045957 0.         0.0703855  0.         0.09456023\n",
      "  0.         0.01671482]\n",
      " [0.00246808 0.09610023 0.08574116 0.06107258 0.06212572 0.01112134\n",
      "  0.0817503  0.07705903 0.13927416 0.06998187 0.03694651 0.\n",
      "  0.07654787 0.02045957 0.         0.0703855  0.         0.09456023\n",
      "  0.         0.01671482]\n",
      " [0.00246808 0.09610023 0.08574116 0.06107258 0.06212572 0.01112134\n",
      "  0.0817503  0.07705903 0.13927416 0.06998187 0.03694651 0.\n",
      "  0.07654787 0.02045957 0.         0.0703855  0.         0.09456023\n",
      "  0.         0.01671482]\n",
      " [0.00246808 0.09610023 0.08574116 0.06107258 0.06212572 0.01112134\n",
      "  0.0817503  0.07705903 0.13927416 0.06998187 0.03694651 0.\n",
      "  0.07654787 0.02045957 0.         0.0703855  0.         0.09456023\n",
      "  0.         0.01671482]\n",
      " [0.00246808 0.09610023 0.08574116 0.06107258 0.06212572 0.01112134\n",
      "  0.0817503  0.07705903 0.13927416 0.06998187 0.03694651 0.\n",
      "  0.07654787 0.02045957 0.         0.0703855  0.         0.09456023\n",
      "  0.         0.01671482]\n",
      " [0.00246808 0.09610023 0.08574116 0.06107258 0.06212572 0.01112134\n",
      "  0.0817503  0.07705903 0.13927416 0.06998187 0.03694651 0.\n",
      "  0.07654787 0.02045957 0.         0.0703855  0.         0.09456023\n",
      "  0.         0.01671482]\n",
      " [0.00246808 0.09610023 0.08574116 0.06107258 0.06212572 0.01112134\n",
      "  0.0817503  0.07705903 0.13927416 0.06998187 0.03694651 0.\n",
      "  0.07654787 0.02045957 0.         0.0703855  0.         0.09456023\n",
      "  0.         0.01671482]]\n",
      "best_score: 0.004486362561372005\n",
      "curve: [0.004486362561372005 0.004486362561372005 0.004486362561372005\n",
      " 0.004486362561372005 0.004486362561372005 0.004486362561372005\n",
      " 0.004486362561372005 0.004486362561372005 0.004486362561372005\n",
      " 0.004486362561372005]\n"
     ]
    }
   ],
   "source": [
    "mymfo=MFO(pop,max_i,dim,ub,lb,chgi,chg300,index2codes,p,2)\n",
    "\n",
    "best_pos2,best_score2,curve2=mymfo.run()\n",
    "\n",
    "print('best_pos:',best_pos2)\n",
    "print('best_score:',best_score2)\n",
    "print('curve:',curve2)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a68c541f-a0e0-4738-bc3f-c175abef3bdd",
   "metadata": {},
   "source": [
    "评价指标"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "808ab84a-b47c-4ec2-892e-bb63bb17c9c4",
   "metadata": {},
   "outputs": [],
   "source": [
    "x=best_pos2[-1]\n",
    "eva_index=get_index(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "ab5a8d21-61da-434b-b642-3b4d406ec73f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'跟踪误差': 0.00448369694341344,\n",
       " '年化收益率': 0.05395312450361889,\n",
       " '年化波动率': 0.15553480168185776,\n",
       " '夏普比率': 0.2665199303009376}"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "eva_index"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "3e139c46-5480-4496-8997-50e423f3a3b2",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1.0023089469281752"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sum(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "70656ded",
   "metadata": {},
   "source": [
    "总结：由于有等式约束，惩罚因子设置影响优化结果，因此采用随机优化算法可能不太合适"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
